package com.mldong.modules.sys.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PageUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.pattern.CronPattern;
import cn.hutool.cron.task.Task;
import com.mldong.base.CommonPage;
import com.mldong.exception.ServiceException;
import com.mldong.modules.sys.service.TimerService;
import com.mldong.timer.TimerCache;
import com.mldong.timer.TimerModel;
import com.mldong.timer.TimerStateEnum;
import com.mldong.timer.TimerTaskRunner;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class TimerServiceImpl implements TimerService {
    private final Map<String, TimerTaskRunner> timerTaskRunnerMap;
    private final TimerCache timerCache;
    @Override
    public void stop(String name) {
        TimerTaskRunner timerTaskRunner = getTimerTaskRunner(name);
        if(timerTaskRunner == null) return;
        String timerId = timerTaskRunner.getClass().getSimpleName();
        CronUtil.remove(timerId);
        TimerModel timerModel = timerCache.get(timerId);
        if(timerModel != null){
            timerModel.setState(TimerStateEnum.STOP.getCode());
            timerCache.put(timerModel.getId(),timerModel);
        }
    }

    @Override
    public void start(String name) {
        Task task = CronUtil.getScheduler().getTask(name);
        TimerTaskRunner timerTaskRunner = getTimerTaskRunner(name);
        if(task == null && timerTaskRunner!=null){
            TimerModel timerModel = timerCache.get(timerTaskRunner.getClass().getSimpleName());
            if(timerModel == null){
                timerModel = new TimerModel().build(timerTaskRunner);
            } else {
                timerModel.setState(TimerStateEnum.RUNNING.getCode());
                timerCache.put(timerModel.getId(),timerModel);
            }
            // 定义hutool的任务
            task = timerTaskRunner::action;
            // 开始执行任务
            CronUtil.schedule(timerModel.getId(), timerModel.getRedisCron(), task);

        }
    }

    @Override
    public CommonPage<TimerModel> page(Dict param) {
        List<TimerModel> timerModelList = new ArrayList<>();
        List<TimerModel> finalTimerModelList = timerModelList;
        timerTaskRunnerMap.keySet().forEach(key -> {
            TimerTaskRunner timerTaskRunner = timerTaskRunnerMap.get(key);
            TimerModel timerModel = timerCache.get(timerTaskRunner.getClass().getSimpleName());
            if (timerModel != null && !timerTaskRunner.isXxlJob()) {
                finalTimerModelList.add(timerModel);
            }
        });
        // param.getStr("keywords") 对timerModelList进行过滤
        if (StrUtil.isNotEmpty(param.getStr("keywords"))) {
            timerModelList = timerModelList.stream().filter(timerModel -> {
                return StrUtil.containsAnyIgnoreCase(timerModel.getTimerName(), param.getStr("keywords"))
                        || StrUtil.containsAnyIgnoreCase(timerModel.getRemark(), param.getStr("keywords"));
            }).collect(Collectors.toList());
        }
        // param.getInt("m_EQ_state")对timerModelList进行过滤
        if (param.getInt("m_EQ_state") != null) {
            timerModelList = timerModelList.stream().filter(timerModel -> {
                return param.getInt("m_EQ_state").equals(timerModel.getState());
            }).collect(Collectors.toList());
        }

        int pageNum = param.get("pageNum", 1);
        int pageSize = param.get("pageSize", 10);
        int start = PageUtil.getStart(pageNum-1, pageSize);
        int end = Math.min(start + pageSize, timerModelList.size());
        // 确保 start 不大于 end
        if (start > end) {
            start = end;
        }
        List<TimerModel> pageRows = timerModelList.subList(start, end);

        CommonPage<TimerModel> page = new CommonPage<>();
        page.setPageNum(pageNum);
        page.setPageSize(pageSize);
        page.setRecordCount(timerModelList.size());
        page.setRows(pageRows);
        page.setTotalPage(PageUtil.totalPage(timerModelList.size(), pageSize));
        return page;
    }

    @Override
    public void reset(List<String> names) {
        if(CollectionUtil.isEmpty(names)) {
            names = CollectionUtil.newArrayList(timerCache.getAllKeys());
        }
        names.forEach(name->{
            TimerModel timerModel = timerCache.get(name);
            if(timerModel!=null){
                timerTaskRunnerMap.keySet().forEach(key -> {
                    if(StrUtil.equalsIgnoreCase(name, key)){
                        TimerTaskRunner timerTaskRunner = timerTaskRunnerMap.get(key);
                        if(!ObjectUtil.equals(timerModel.getRedisCron(),timerTaskRunner.getCron())){
                            // 不一致，且为停止状态，才能重置redisCron
                            if(ObjectUtil.equals(timerModel.getState(),TimerStateEnum.STOP.getCode())){
                                timerModel.setRedisCron(timerTaskRunner.getCron());
                            }
                        }
                        timerModel.setCron(timerTaskRunner.getCron());
                        timerModel.setRemark(timerTaskRunner.getName());
                        timerCache.put(timerModel.getId(),timerModel);
                    }
                });
            }
        });


    }

    @Override
    public void update(String id, String remark, String redisCron) {
        if(StrUtil.isEmpty(redisCron)){
            ServiceException.throwBiz(99999999,"redisCron是必填项");
        }
        // 校验 cron 表达式是否合法
        try {
            new CronPattern(redisCron);
        } catch (Exception e) {
            ServiceException.throwBiz(99999999, "cron表达式不合法");
        }
        TimerTaskRunner timerTaskRunner = getTimerTaskRunner(id);
        if(timerTaskRunner == null) return;
        TimerModel timerModel = timerCache.get(timerTaskRunner.getClass().getSimpleName());
        if(timerModel == null) return;
//        if(TimerStateEnum.RUNNING.getCode().equals(timerModel.getState())){
//            stop(id);
//            start(id);
//        }
        timerModel.setRemark(remark);
        if(!TimerStateEnum.RUNNING.getCode().equals(timerModel.getState())){
            timerModel.setRedisCron(redisCron);
        }
        timerCache.put(timerModel.getId(),timerModel);
    }

    @Override
    public TimerModel getById(String id) {
        TimerTaskRunner timerTaskRunner = getTimerTaskRunner(id);
        if(timerTaskRunner == null) return null;
        String timerId = timerTaskRunner.getClass().getSimpleName();
        return timerCache.get(timerId);
    }
    @Override
    public void executeImmediate(String id) {
        TimerTaskRunner timerTaskRunner = getTimerTaskRunner(id);
        if(timerTaskRunner != null){
            timerTaskRunner.action();
        }
    }
    private TimerTaskRunner getTimerTaskRunner(String name) {
        return timerTaskRunnerMap.get(StrUtil.toCamelCase(StrUtil.toUnderlineCase(name)));
    }
}
